/* Copyright (c) 2009-2010, Sean A.O. Harney <sharney3@gmail.com> */


/* NOTE: kernel src file fs/proc/task_mmu.c always prints the smaps file values with kB units */

#include "omf.h"


/* prototypes */
void sigalrm_handler(int signum);


bool memusage_init()
{
    struct sigaction sa;
    struct itimerval nit;

    sa.sa_handler = sigalrm_handler;
    sa.sa_flags = 0;
    sigemptyset(&sa.sa_mask);
    if (sigaction(SIGALRM, &sa, NULL) < 0)
	return false;


    nit.it_interval.tv_sec = 0;
    nit.it_interval.tv_usec = 500000;
    nit.it_value.tv_sec = 0;
    nit.it_value.tv_usec = 500000;	// 0.5 second.
    /* raises SIGALRM */
    if (setitimer(ITIMER_REAL, &nit, NULL) < 0)
	return false;

    return true;
}

bool get_memusage(pid_t pid, struct st_memusage * retval)
{
#ifdef HAVE_SMAPS
    char smaps_fname[256];
    char line[1024];
    char *saveptr, *token1, *token2;
    FILE *fp;

    retval->size = 0;
    retval->rss = 0;
    retval->pss = 0;

    snprintf(smaps_fname, sizeof(smaps_fname), "/proc/%d/smaps", pid);
    fp = fopen(smaps_fname, "r");
    if (fp == NULL)
      {
	  perror("fopen()");
	  return false;
      }

    while (1)
      {
	  if (fgets(line, sizeof(line), fp) == NULL)
	    {
		if (ferror(fp))
		  {
		      perror("fgets()");
		      fclose(fp);
		      return false;
		  }
		// else EOF
		break;
	    }

	  token1 = strtok_r(line, " \t", &saveptr);
	  if (token1 == NULL)
	    {
		fclose(fp);
		return false;

	    }
	  token2 = strtok_r(NULL, " \t", &saveptr);
	  if (token2 == NULL)
	    {
		fclose(fp);
		return false;
	    }
//NOTE: token2 might not be integer if on first line of a smaps stanza.
	  if (!strcmp(token1, "Size:"))
	      retval->size += atoi(token2);
	  else if (!strcmp(token1, "Rss:"))
	      retval->rss += atoi(token2);
	  if (!strcmp(token1, "Pss:"))
	      retval->pss += atoi(token2);
      }

    fclose(fp);
    debug2_printf
	("Totals for pid %d (in kB):\n\tSize:\t%d\n\tRss:\t%d\n\tPss:\t%d\n",
	 pid, retval->size, retval->rss, retval->pss);

    return true;

#else
    error_println("No support for proc smaps file!\n");
    return false;
#endif
}


void sigalrm_handler(int signum)
{

    struct timeval running_time;
    struct st_memusage memusage;
    pid_t pid;
    char dirname[512];
    char line[512];


    sigchld_block();		//without this sigchld can interrupt
    debug2_printf("ALRM!\n");

    if (get_omf_running_time(&running_time) == false)
      {
	  sigchld_unblock();
	  return;
      }
//TODO: for each running task, append it's memusage.dat

    pid = 21888;

    if (get_memusage(pid, &memusage) == false)
      {
	  error_println("get_memusage()");
	  sigchld_unblock();
	  return;
      }

    if (outputlog_get_dirname_from_txt(pid, dirname,
				       sizeof(dirname)) == false)
      {
	  error_println("couln't find subdir\n");	//shouldn't get here
	  strcpy(dirname, "/tmp/");
	  //sigchld_unblock();
	  //      return;
      }
    //printf("dirname =%s\n", dirname);
    snprintf(line, sizeof(line), "%ld.%.3ld\t%d\t%d\t%d\n",
	     running_time.tv_sec, running_time.tv_usec, memusage.size,
	     memusage.rss, memusage.pss);

    outputlog_append_memusage_dat(dirname, line);	//checks that there is no -N flag
    sigchld_unblock();
}
